package com.dj.service.serviceimpl;

import ca.uhn.fhir.rest.param.StringParam;
import com.dj.bean.*;
import com.dj.constant.FhirContextContstant;
import com.dj.repository.EncounterRespository;
import com.dj.repository.PatientRespository;
import com.dj.repository.ProcedureRequestHistoryRepository;
import com.dj.repository.ProcedureRequestRespository;
import com.dj.service.ProcedureRequestService;
import org.apache.commons.collections4.CollectionUtils;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.ProcedureRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author cyf
 * @description
 * @create 2018-06-27 13:45
 **/

@Service
public class ProcedureRequestServiceImpl implements ProcedureRequestService {

    private static final Logger logger = LoggerFactory.getLogger(ProcedureRequestServiceImpl.class);

    @Autowired
    private ProcedureRequestRespository procedureRequestRespository;

    @Autowired
    private PatientRespository patientRespository;

    @Autowired
    private EncounterRespository encounterRespository;

    @Autowired
    private ProcedureRequestHistoryRepository procedureRequestHistoryRepository;


    @Transactional
    @Override
    public IdType saveProcedureRequest(ProcedureRequest procedureRequest) {
        //将procedureRequest转换为json串
        String content = FhirContextContstant.getParse().encodeResourceToString(procedureRequest);
        //获得实体对象
        ProcedureRequestBean procedureRequestBean =
                getProcedureRequestBean(procedureRequest, content,
                        FhirContextContstant.INITIAL_VERSION_NUMBER, null);

        //保存到数据库
        ProcedureRequestBean saveProcedureRequestBean = null;
        try {
            saveProcedureRequestBean = procedureRequestRespository.save(procedureRequestBean);
            logger.info("Save the current version of success");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Exception，Save the current version of error,", e);
        }
        if (saveProcedureRequestBean != null) {
            String id = saveProcedureRequestBean.getId();
            //保存历史记录
            if (saveHistory(content, id, FhirContextContstant.INITIAL_VERSION_NUMBER)) {
                logger.info("Save the historical version of success");
                return new IdType("ProcedureRequest", id, FhirContextContstant.INITIAL_VERSION_NUMBER);
            }
        }
        return null;

    }


    @Transactional
    @Override
    public IdType updateProcedureRequest(String id, ProcedureRequest procedureRequest) {

        logger.info("updateProcedureRequest id is {}", id);
        IdType idType = new IdType();

        //查询当前库和历史库是否存在id的记录
        Optional<ProcedureRequestBean> result = null;
        ProcedureRequestHistoryBean procedureRequestHistoryBean = null;
        String version = null;
        try {
            result = procedureRequestRespository.findById(id);
            version = result.get().getVersion();
            procedureRequestHistoryBean = procedureRequestHistoryRepository.findByValidVersionIdAndVersion(id, version);
        } catch (Exception e) {
            logger.error("Exception, Current object existence, the encounter id is {}",id, e);
        }
        //判断当前是否存在
        if (!result.isPresent()) {
            //记录不存在
            logger.error("ProcedureRequest id={} is not present!!!", id);
            return idType;
        }

        //判断历史存在
        if (procedureRequestHistoryBean == null) {
            ProcedureRequestBean procedureRequestBean = result.get();
            saveHistory(procedureRequestBean.getContent(), procedureRequestBean.getId(), procedureRequestBean.getVersion());
        }


        String content = FhirContextContstant.getParse().encodeResourceToString(procedureRequest);

        version = String.valueOf(Integer.valueOf(version) + 1);
        ProcedureRequestBean procedureRequestBean = getProcedureRequestBean(procedureRequest, content, version, result.get());
        procedureRequestBean.setId(id);
            ProcedureRequestBean save = null;
            try {
                save = procedureRequestRespository.save(procedureRequestBean);
                logger.info("Save the current version of success");
            } catch (Exception e) {
                logger.error("Exception，Save the current version of error,", e);
            }
            if (save != null) {
                if (saveHistory(content, save.getId(), version)) {
                    logger.info("Save the historical version of success");
                    return new IdType("ProcedureRequest", save.getId(), save.getVersion());
                }
            }

        return idType;
    }

    /**
     * 保存历史记录
     * @param content
     * @param id
     * @param version
     * @return
     */
    private boolean saveHistory(String content, String id, String version) {
        logger.info("saveHistory content is {}, id is {}, version is {}",content,id,version);
        //保存历史库
        ProcedureRequestHistoryBean procedureRequestHistoryBean = new ProcedureRequestHistoryBean();
        procedureRequestHistoryBean.setValidVersionId(id);
        procedureRequestHistoryBean.setVersion(version);
        procedureRequestHistoryBean.setCreateTime(new Date());
        procedureRequestHistoryBean.setContent(content);
        ProcedureRequestHistoryBean saveHistory = null;
        try {
            saveHistory = procedureRequestHistoryRepository.save(procedureRequestHistoryBean);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ProcedureRequestHistory saveHistory error, the cause is {}",e.getCause());
        }
        return saveHistory != null;
    }



    @Override
    public ProcedureRequest getById(String id) {
        Optional<ProcedureRequestBean> result = null;
        try {
            result = procedureRequestRespository.findById(id);
            logger.info("Query the current version success, the ProcedureRequest id {}", id);
        } catch (Exception e) {
            logger.error("Exception, Query the current version error, the ProcedureRequest id {}" , e, id);
        }
        if (result.isPresent()) {
            ProcedureRequestBean procedureRequestBean = result.get();
            return getProcedureRequest(procedureRequestBean.getContent(), procedureRequestBean.getId(), procedureRequestBean.getVersion());
        } else {
            logger.info("procedureRequest getById  id={} is not exist!!!", id);
            return new ProcedureRequest();
        }
    }



    @Override
    public List<ProcedureRequest> getByCode(StringParam code) {
        String name = code.getValue();
        //获得查询结果
        List<ProcedureRequestBean> patientEntityList = null;
        try {
            //查询检查项目的编码  code
            patientEntityList = procedureRequestRespository.findByItemName(name);
            logger.info("Query success based on code");
        } catch (Exception e) {
            logger.error("Exception, According to the code query error, the code is {}", name, e);
        }
        return getProcedureRequestList(patientEntityList);
    }


    @Override
    public ProcedureRequest getByIdAndVersion(String id, String version) {
        ProcedureRequestHistoryBean procedureRequestHistoryBean = null;
        try {
            procedureRequestHistoryBean = procedureRequestHistoryRepository.findByValidVersionIdAndVersion(id, version);
            logger.info("Query the specified historical version success");
        } catch (Exception e) {
            logger.error("Exception, Query the specified historical version error, the id is {}, the version is {}",e, version);
        }
        if (procedureRequestHistoryBean != null) {
            return getProcedureRequest(procedureRequestHistoryBean.getContent(), id, version);
        } else {
            logger.error("procedureRequestHistoryRepository.findByValidVersionIdAndVersion ProcedureRequest id={} is not exist!!!", id);
            return new ProcedureRequest();
        }
    }



    private ProcedureRequest getProcedureRequest(String content, String id, String version) {
        ProcedureRequest procedureRequest = FhirContextContstant.getParse().parseResource(ProcedureRequest.class, content);
        IdType idType = new IdType("ProcedureRequest", id, version);
        procedureRequest.setId(idType);
        procedureRequest.setMeta(new Meta().setLastUpdated(getLastUpdatTime(id)));

        return procedureRequest;
    }


    private ProcedureRequestBean getProcedureRequestBean(ProcedureRequest procedureRequest, String content,
                                                         String version, ProcedureRequestBean procedureRequestBean) {
        Date date = new Date();
        if(procedureRequestBean == null){
            procedureRequestBean = new ProcedureRequestBean();
            procedureRequestBean.setCreateTime(date);
        }
        procedureRequestBean.setVersion(version);
        procedureRequestBean.setContent(content);
        //设置项目编码
        //String code = procedureRequest.getCode().getCodingFirstRep().getCode();
        String code = procedureRequest.getCode().getCodingFirstRep().getDisplay();
        procedureRequestBean.setItemName(code);
        //设置更新时间
        procedureRequestBean.setParam1(date);
        return procedureRequestBean;
    }


    private List<ProcedureRequest> getProcedureRequestList(List<ProcedureRequestBean> procedureRequestBeanList) {
        if (CollectionUtils.isNotEmpty(procedureRequestBeanList)) {
            return procedureRequestBeanList.stream()
                    .filter(procedureRequestBean -> procedureRequestBean != null)
                    .map(procedureRequestBean -> getProcedureRequest(procedureRequestBean.getContent(), procedureRequestBean.getId(), procedureRequestBean.getVersion()))
                    .collect(Collectors.toList());
        } else {
            return Collections.emptyList();
        }
    }





    @Override
    public boolean deleteProcedureRequest(String id) {

        Optional<ProcedureRequestBean> result = null;
        try {
            //先查询是否存在
            result = procedureRequestRespository.findById(id);
        } catch (Exception e) {
            logger.error("Exception, Delete failure according to ID, the id is {}",id, e);
        }

        if (result.isPresent()) {
            try {
                procedureRequestRespository.deleteById(id);
                logger.info("deleteProcedureRequest is success");
            } catch (Exception e) {
                logger.error("Exception, Delete historical version failure, the id is {}",id, e);
            }
            return  true;
        } else {
            //记录不存在
            logger.info("deleteProcedureRequest error , ProcedureRequest id={} is not exist!!!", id);
            return false;
        }
    }

    @Override
    public Date getLastUpdatTime(String id) {
        Optional<ProcedureRequestBean> result = procedureRequestRespository.findById(id);
        if (!result.isPresent()) {
            logger.error("ProcedureRequest findById error, {} is not exist!!!", id);
            return new Date();
        }
        return result.get().getParam1();
    }

    @Override
    public Date getHistoryLastUpdatTime(String id, String version) {
        ProcedureRequestHistoryBean result = procedureRequestHistoryRepository.findByValidVersionIdAndVersion(id, version);
        if(result!=null){
            return result.getCreateTime();
        } else {
            return null;
        }
    }

    @Override
    public List<ProcedureRequest> getAllProcedureRequestById(String id) {
        List<ProcedureRequestHistoryBean> procedureRequestHistoryBeanList =
                procedureRequestHistoryRepository.findByValidVersionId(id);
        return getProcedureRequestHistoryLists(procedureRequestHistoryBeanList);
    }

    @Override
    public Boolean isExist(String patientId, String encounterId) {
        boolean flag = false;
        if(!patientId.isEmpty() && !encounterId.isEmpty()){
            Optional<PatientBean> patientResult = patientRespository.findById(patientId);
            if(patientResult.isPresent()){
                Optional<EncounterBean> encounterResult = encounterRespository.findById(encounterId);
                if(encounterResult.isPresent()){
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 返回历史集合
     * @param procedureRequestHistoryBeanList
     * @return
     */
    private List<ProcedureRequest> getProcedureRequestHistoryLists(List<ProcedureRequestHistoryBean> procedureRequestHistoryBeanList) {
        if (CollectionUtils.isNotEmpty(procedureRequestHistoryBeanList)) {
            logger.info("Query all historical versions of success");
            List<ProcedureRequest> list = procedureRequestHistoryBeanList.stream()
                    .filter(it -> it != null)
                    .map(it -> getHistoryProcedureRequest(it.getContent(), it.getValidVersionId(), it.getVersion()))
                    .collect(Collectors.toList());

            return list;
        } else {
            logger.info("getProcedureRequestHistoryLists is empty");
            return Collections.emptyList();
        }
    }

    private ProcedureRequest getHistoryProcedureRequest(String content, String id, String version) {
        ProcedureRequest procedureRequest = FhirContextContstant.getParse().parseResource(ProcedureRequest.class, content);
        IdType idType = new IdType("ProcedureRequest", id, version);
        procedureRequest.setId(idType);
        procedureRequest.setMeta(new Meta().setLastUpdated(getHistoryLastUpdatTime(id,version)));

        return procedureRequest;
    }


//    @Transactional
//    @Override
//    public boolean deleteProcedureRequest(ProcedureRequest procedureRequest) {
//        Boolean retVal = false;
//        IdType theId = procedureRequest.getIdElement();
//        String id = theId.getIdPart();
//        String version = theId.getVersionIdPart();
//
//        ProcedureRequestHistoryBean procedureRequestHistoryBean = null;
//        try {
//            procedureRequestHistoryBean = procedureRequestHistoryRepository.findByValidVersionIdAndVersion(id, version);
//        } catch (Exception e) {
//            e.printStackTrace();
//            logger.error("query error, the cause is {}",e.getCause());
//        }
//        boolean saveHistory;
//        if (procedureRequestHistoryBean == null) {
//            String content = FhirContextContstant.getParse().encodeResourceToString(procedureRequest);
//            saveHistory = saveHistory(content, id, version);
//        } else {
//            saveHistory = true;
//        }
//        if (saveHistory) {
//            try {
//                procedureRequestRespository.deleteById(id);
//            } catch (Exception e) {
//                e.printStackTrace();
//                logger.error("delete error, the cause is {}",e.getCause());
//            }
//            retVal = true;
//        }
//        return retVal;
//    }
}
